using System;
using System.Collections.Generic;

namespace LegoBotPrimaAbstractions
{
    public static class MathUtil
    {
        public static double DegreesToRadians(double degrees)
        {
            return degrees * (Math.PI / 180.0);
        }
        public static double RadiansToDegrees(double radians)
        {
            return radians * (180.0 / Math.PI);
        }
        public static double AnglesDiff(double firstAngle, double secondAngle)
        {
            var difference = secondAngle - firstAngle;
            while (difference < -180) difference += 360;
            while (difference > 180) difference -= 360;
            return difference;
        }

        private static volatile int _seed;
        public static bool RandomBooleanWithProbability(double probability)
        {
            Ensure.IsWithin(probability, 0, 1, "probability");
            _seed += DateTime.Now.Millisecond;
            var random = new Random(_seed);
            return random.NextDouble() < probability;
        }

        public static double RandomDoubleFromRange(double from, double to)
        {
            _seed += DateTime.Now.Millisecond;
            var random = new Random(_seed);
            var diff = Math.Abs(from - to);
            
            return random.NextDouble() * diff + from;
        }

        public static int RandomIntFromRange(int from, int to)
        {
            _seed += DateTime.Now.Millisecond;
            var random = new Random(_seed);
            return random.Next(from, to + 1);
        }


        public static double CalculateVariance<T>(IEnumerable<T> data, Func<T, double> extractNumber)
        {
            var sumOfSquared = 0.0;
            var sum = 0.0;
            var length = 0;
            foreach (var variable in data)
            {
                var number = extractNumber(variable);
                sumOfSquared += (number * number);
                sum += number;
                length++;
            }
            if (length <= 1) return 0;
            return CalculateVariance(sumOfSquared, sum, length);
        }
        public static double CalculateStandardDeviation<T>(IEnumerable<T> data, Func<T, double> extractNumber)
        {
            var variance = CalculateVariance(data, extractNumber);
            if (variance <= 1) return 0;
            return Math.Sqrt(variance);
        }
        public static double CalculateVariance(double sumOfSquared, double sum, int length)
        {
            if (length <= 0)
            {
                throw new ArgumentException("CalculateVariance cannot accept length equal to or less than one", "length");
            }
            return (sumOfSquared - ((sum * sum) / length)) / (length - 1);
        }
        public static double CalculateStandardDeviation(double sumOfSquared, double sum, int length)
        {
            var variance = CalculateVariance(sumOfSquared, sum, length);
            return Math.Sqrt(variance);
        }
    }
}